#include <dirent.h>
#include <utility.h>
#include <iostream>
#include <ostream>
#include <sys/stat.h>
#include <sys/types.h>
#include <vector>

namespace PaddleOCR {

    std::vector<std::string> Utility::ReadDict(const std::string& path) {
        std::ifstream in(path);
        std::string line;
        std::vector<std::string> m_vec;
        if (in) {
            while (getline(in, line)) {
                m_vec.push_back(line);
            }
        }
        else {
            std::cout << "no such label file: " << path << ", exit the program..."
                << std::endl;
            exit(1);
        }
        return m_vec;
    }

    void Utility::VisualizeBboxes(
        const cv::Mat& srcimg,
        const std::vector<std::vector<std::vector<int>>>& boxes) {
        cv::Mat img_vis;
        srcimg.copyTo(img_vis);
        for (int n = 0; n < boxes.size(); n++) {
            cv::Point rook_points[4];
            for (int m = 0; m < boxes[n].size(); m++) {
                rook_points[m] = cv::Point(int(boxes[n][m][0]), int(boxes[n][m][1]));
            }

            const cv::Point* ppt[1] = { rook_points };
            int npt[] = { 4 };
            cv::polylines(img_vis, ppt, npt, 1, 1, CV_RGB(0, 255, 0), 2, 8, 0);
        }

        cv::imwrite("./ocr_vis.png", img_vis);
        std::cout << "The detection visualized image saved in ./ocr_vis.png"
            << std::endl;
    }

    // list all files under a directory
    void Utility::GetAllFiles(const char* dir_name,
        std::vector<std::string>& all_inputs) {
        if (NULL == dir_name) {
            std::cout << " dir_name is null ! " << std::endl;
            return;
        }
        struct stat s;
        stat(dir_name, &s);
        if (!S_ISDIR(s.st_mode)) {
            std::cout << "dir_name is not a valid directory !" << std::endl;
            all_inputs.push_back(dir_name);
            return;
        }
        else {
            struct dirent* filename; // return value for readdir()
            DIR* dir;                // return value for opendir()
            dir = opendir(dir_name);
            if (NULL == dir) {
                std::cout << "Can not open dir " << dir_name << std::endl;
                return;
            }
            std::cout << "Successfully opened the dir !" << std::endl;
            while ((filename = readdir(dir)) != NULL) {
                if (strcmp(filename->d_name, ".") == 0 ||
                    strcmp(filename->d_name, "..") == 0)
                    continue;
                // img_dir + std::string("/") + all_inputs[0];
                all_inputs.push_back(dir_name + std::string("/") +
                    std::string(filename->d_name));
            }
        }
    }

    cv::Mat Utility::GetRotateCropImage(const cv::Mat& srcimage,
        std::vector<std::vector<int>> box) {
        cv::Mat image;
        srcimage.copyTo(image);
        std::vector<std::vector<int>> points = box;

        int x_collect[4] = { box[0][0], box[1][0], box[2][0], box[3][0] };
        int y_collect[4] = { box[0][1], box[1][1], box[2][1], box[3][1] };
        int left = int(*std::min_element(x_collect, x_collect + 4));
        int right = int(*std::max_element(x_collect, x_collect + 4));
        int top = int(*std::min_element(y_collect, y_collect + 4));
        int bottom = int(*std::max_element(y_collect, y_collect + 4));

        cv::Mat img_crop;
        image(cv::Rect(left, top, right - left, bottom - top)).copyTo(img_crop);

        for (int i = 0; i < points.size(); i++) {
            points[i][0] -= left;
            points[i][1] -= top;
        }

        int img_crop_width = int(sqrt(pow(points[0][0] - points[1][0], 2) +
            pow(points[0][1] - points[1][1], 2)));
        int img_crop_height = int(sqrt(pow(points[0][0] - points[3][0], 2) +
            pow(points[0][1] - points[3][1], 2)));

        cv::Point2f pts_std[4];
        pts_std[0] = cv::Point2f(0., 0.);
        pts_std[1] = cv::Point2f(img_crop_width, 0.);
        pts_std[2] = cv::Point2f(img_crop_width, img_crop_height);
        pts_std[3] = cv::Point2f(0.f, img_crop_height);

        cv::Point2f pointsf[4];
        pointsf[0] = cv::Point2f(points[0][0], points[0][1]);
        pointsf[1] = cv::Point2f(points[1][0], points[1][1]);
        pointsf[2] = cv::Point2f(points[2][0], points[2][1]);
        pointsf[3] = cv::Point2f(points[3][0], points[3][1]);

        cv::Mat M = cv::getPerspectiveTransform(pointsf, pts_std);

        cv::Mat dst_img;
        cv::warpPerspective(img_crop, dst_img, M,
            cv::Size(img_crop_width, img_crop_height),
            cv::BORDER_REPLICATE);

        if (float(dst_img.rows) >= float(dst_img.cols) * 1.5) {
            cv::Mat srcCopy = cv::Mat(dst_img.rows, dst_img.cols, dst_img.depth());
            cv::transpose(dst_img, srcCopy);
            cv::flip(srcCopy, srcCopy, 0);
            return srcCopy;
        }
        else {
            return dst_img;
        }
    }

} // namespace PaddleOCR